Computer programs behave differently depending on the input they receive. Sometimes it is necessary for a computer program to receive identical input each time it is run. For example, a customer may receive an error message while using the computer program. A support technician needs to be able to reproduce the error to debug the computer program. The support technician may ask the customer to provide step-by-step instructions that lead to the error message. For example, the customer may tell the technician that clicking the Save button when Caps Lock is enabled causes the computer program to crash. The technician will then note that the steps to reproduce the error are: 1) enable Caps Lock; then 2) click the Save button. The input to the program—enabling Caps Lock and then clicking Save—may consistently crash the program every time the program runs.
In some situations, a computer program may receive non-deterministic input that causes the program to behave differently each time the program runs. Network input is a common source of non-deterministic input. The program may be susceptible to crashing given a specific sequence of input events that must be reproduced exactly to trigger the crash while debugging or performing other testing.
Non-deterministic input also hinders attack mitigation analysis. For example, certain network traffic received by a program may be known to cause buffer overflow on a particular operating system on a particular computer architecture. A buffer overflow is an example of a severe program bug because malicious programs can exploit them over a network to infect or damage the computer running the program that is susceptible to the buffer overflow. To evaluate whether this network traffic can cause the same buffer overflow on other operating systems or computer architectures, the program on each configuration must receive the same network input to test it.
Conventional techniques for reproducing input to a computer program have significant shortcomings. For example, IOapps tools use library interposition to record and playback system events. IOapps interposes a recorder program between a computer program executable and an operating system's library (e.g., “libc”) to trace or intercept system calls. However, like most record-and-replay implementations, IOapps records some libc function calls (currently 20) and attempts to re-execute (replay) them exactly as recorded. IOapps is heavyweight, interposing only on a subset of low-level input/output (“I/O”), and inflexible, not providing any options for allowing network input playback.
Jockey is another conventional record-and-replay implementation. Jockey operates at an even lower level than IOapps, instrumenting operating system level system calls. Jockey does not provide high-level library interposition.
Another record-and-replay implementation, R2, requires that the computer program be developed for the system. Software developers must instrument their computer code with R2′ s record-and-replay system in mind. R2 cannot support computer programs that have not been instrumented for R2.
In view of the foregoing, it may be understood that there may be significant problems and shortcomings associated with conventional technologies for redirecting I/O.